package org.marketlive.entity;

/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.hibernate.Criteria;
import org.marketlive.entity.attributes.IAttributeHome;

import java.util.Collection;
import java.util.Iterator;

/**
 * Provides CRUD operations on entities.
 * Also provides means for associating attribute pages to entities.
 */
public interface IEntityHome {

    /**
     * Returns the name of the type of entity that this <code>IEntityHome</code> manages.
     *
     * @return the type of entity that calls this <code>IEntityHome</code> home
     */
    String getEntityType();

    /**
     * Defines an attribute page for entities managed by this <code>IEntityHome</code>.
     * The page may be an <code>IAttributePage</code> or an <code>IComplexAttributePage</code>.
     * It must have a public default constructor.
     *
     * @param name  the name of the attribute page
     * @param clazz the class that implements the attribute page
     */
    void definePage(String name, Class clazz);
    
    /**
     * Defines an attribute page for entities managed by this <code>IEntityHome</code>
     * that can be localized. The page may be an <code>IAttributePage</code> or an 
     * <code>IComplexAttributePage</code>. It must have a public default constructor.
     *
     * @param name  the name of the attribute page
     * @param clazz the class that implements the attribute page
     */
    void defineLocalizedPage(String name, Class clazz);
    
    /**
     * Returns a blank page with the given name.
     * The page must have been defined in the context.
     *
     * @param pageName the name of the page to retrieve
     * @return an uninitialized instance of the page with the given name
     */
    IAttributePage getEmptyPage(String pageName);

    /**
     * Checks if the given page name is defined as a localized attribute page.
     * This is a simple check of the localized page definitions and if the
     * page name is not found the method returns false.  This does not mean
     * the page name will be found in the non-localized page definitions.
     *
     * @param pageName the name of the page to retrieve
     * @return true if localized page type
     */
    boolean isLocalizedPage(String pageName);


    /**
     * Returns a primary key based on the given string.
     * The key is specific to the type of entity this <code>IEntityHome</code> manages.
     *
     * @param pkString the string representation of the primary key
     * @return an <code>IPrimaryKey</code> based on <code>pkString</code>
     */
    IPrimaryKey getPk(String pkString);

    /**
     * Returns an empty transient instance of the entity.
     * The entity can be persisted later with a call to <code>create(IEntity)</code>.
     *
     * @param pk the <code>IPrimaryKey</code> of the entity to create.  Can be null.
     * @return a transient instance of an <code>IEntity</code>
     */
    IEntity get(IPrimaryKey pk);

    /**
     * Adds the given transient entity to the persistent store.
     *
     * @param entity the entity to insert into the persistent store
     * @return the <code>IPrimaryKey</code> of the created entity
     */
    IPrimaryKey create(IEntity entity);

    /**
     * Updates the given persistent <code>IEntity</code>.
     *
     * @param entity the <code>IEntity</code> to update
     */
    void update(IEntity entity);

    /**
     * Adds the given transient entity to the persistent store.
     *
     * @param entity the entity to insert into the persistent store
     */
    void save(IEntity entity);

    /**
     * Persists the given entity. If the entity was already persistent,
     * performs an update; otherwise, performs an insert.
     *
     * @param entity the <code>IEntity</code> to persist
     */
    void saveOrUpdate(IEntity entity);

    /**
     * Merges a detached object with the persisted entity.
     *
     * @param entity the <code>IEntity</code> to merge
     */
    <T> T merge(T entity);

    /**
     * Permanently deletes the given entity from the underlying persistence store.
     * @param entity the <code>IEntity</code> to delete
     */
    void delete(IEntity entity);

    /**
     * Returns the <code>IEntity</code> with the given primary key.
     * The entity returned may be marked inactive or deleted.
     * This method works with <code>IntegerPk</code>s.  If an
     * entity uses a different type of key, its home must overload this method.
     *
     * @param pk the <code>IPrimaryKey</code> of the entity to find
     * @return the <code>IEntity</code> with the given primary key
     * @throws RuntimeException if no <code>IEntity</code> is found for the given key
     */
    IEntity findByPk(IPrimaryKey pk);

    /**
     * Returns the <code>IEntity</code> with the given primary key.
     * This method works with <code>IntegerPk</code>s.  If an
     * entity uses a different type of key, its home must overload this method.
     *
     * @param pk the <code>IPrimaryKey</code> of the entity to get
     * @return the <code>IEntity</code> with the given primary key, or null if none exists
     */
    IEntity getByPk(IPrimaryKey pk);

    /**
     * Finds the entity with the primary key represented by <code>pkString</code>.
     * The string must be generated by calling {@link IPrimaryKey#getAsString()}.
     *
     * @param pkString the string representation of the primary key
     * @return the entity with the specified key, or null if none exists
     */
    IEntity getByPk(String pkString);

    /**
     * Finds the <code>IEntity</code> with the given primary key string.
     * The string must be generated by calling {@link IPrimaryKey#getAsString()}.
     *
     * @param pkString the primary key string of the entity to find
     * @return the <code>IEntity</code> with the given primary key
     * @throws RuntimeException if no <code>IEntity</code> is found for the given key string
     */
    IEntity findByPk(String pkString);

    /**
     * Finds and holds a lock on the <code>IEntity</code> with the given primary key.
     * This method works with <code>IntegerPk</code>s.  If an
     * entity uses a different type of key, its home must overload this method.
     * <p/>
     * This method pessimistically locks the entity, preventing other processes from reading
     * or modifying until the underlying session is closed.  Use judiciously.
     *
     * @param pk the <code>IPrimaryKey</code> of the entity to find
     * @return the <code>IEntity</code> with the given primary key
     * @throws RuntimeException if no <code>IEntity</code> is found for the given key
     */
    IEntity findByPkLock(IPrimaryKey pk);

    /**
     * Returns all the entities managed by this <code>IEntityHome</code>.
     * If no persistent entities exist for this <code>IEntityHome</code>, returns an empty collection.
     *
     * @return a <code>Collection</code> of entities managed by this home. May be empty.
     */
    Collection findAll();

    /**
     * Returns entities that have the given value for the given field.
     *
     * @param value the string value to match
     * @param columnName the name of the column to query
     * @return a <code>Collection</code> of entities that have the given value in <code>columnName</code>
     * @deprecated  This method does not provide support for specifying search criteria on
     * data stored as attribute pages of the entity. As of MarketLive 5.5, use {@link #findByQuery(String)}.
     */
    Collection findByFieldMatch(String columnName, String value);

     /**
      * Execute an HQL query for entities. Important limitation to this feature
      * is that only the target entity should be part of the select clause.  For
      * example if using a IProductHome implementation to select entities
      * be sure to restrict the query to return only Product type entities.
      * A future implementation may enforce this restriction.
      * @param pQueryString a query expressed in HQL.
      * @return a List containing 0 or more entities.
      */
     Collection findByQuery(String pQueryString);

    /**
     * Returns entities that match the given template.
     * The template must be an instance of the entity type to search. For example, to find
     * matching <code>IProduct</code>s, the given template must be an instance of <code>IProduct</code>.
     * The template cannot be null.
     *
     * @param template the instance of an <code>IEntity</code>, with fields initialized to the values
     *        that should be matched
     * @return a <code>Collection</code> of matching entities. May be empty.
     */
   // Collection findMatching(IEntity template);

    /**
     * Creates filtering criteria for entities managed by this <code>IEntityHome</code>.
     *
     * @return a <code>Criteria</code> object
     */
    Criteria createCriteria();

    /**
     * Return the query results as an Iterator. Entities returned are initialized
     * on demand. The first SQL query returns identifiers only.
     *
     * @param pQueryString a query expressed in HQL.
     * @param useCache set whether ORM (e.g Hibernate) session should interact with cache.
     * @return the result iterator
     */
    Iterator findByQueryIterate(String pQueryString, boolean useCache);

    /**
     * Completely clear the underlying ORM (e.g Hibernate) session. Evict all
     * loaded instances and cancel all pending saves, updates and deletions.
     * Do not close open iterators.
     *
     * @param gc suggest the JVM attempt to recycle unused objects
     */
    void sessionClear(boolean gc);

    /**
     * Force the ORM (e.g Hibernate) session to flush. Must be called at the end of a
     * unit of work, before committing the transaction and closing the session. Flushing
     * the session synchronizes the underlying persistent store with persistable state
     * held in memory.
     */
    void sessionFlush();
    
    /**
     * Returns if the session is dirty
     * @return
     */
    public boolean isDirty();

    /**
     * Updates the given persistent <code>IEntity</code> if the session shows it as dirty.
     *
     * @param entity the <code>IEntity</code> to update
     */
    void updateCheckDirty(IEntity entity);

    /**
     * Persists the given entity. If the entity was already persistent,
     * performs an update if the session sees it as dirty; otherwise, performs an insert.
     *
     * @param entity the <code>IEntity</code> to persist
     */
    void saveOrUpdateCheckDirty(IEntity entity);
    
}